import EventSystem from "../event/EventSystem";
import ExcelLib from "./ExcelLib";
import ExcelLibData from "./ExcelLibData";
import ExcelLibDefinition from "./ExcelLibDefinition";
import ExcelLibDefinitionTable from "./ExcelLibDefinitionTable";
import ExcelLibTools from "./ExcelLibTools";
import HeaderData from "./HeaderData";

export default class ExcelLibReader {

    public static FILE_RES_PATH: string = "lib/";
    public static FILE_DEFINITION: string = "_definition.json";

    public static SERVER_DEFINITION_URL: string = "sys/definition";
    public static SERVER_TABLE_URL: string = "sys/getData?name=";
    public static SERVER_VERSION_URL: string = "sys/version";


    private header: HeaderData;
    private excelLibDefinitions: Array<ExcelLibDefinition>;

    private libData: ExcelLibData;
    /**
     * 键值获取定义文件，Key:dataFullName
     */
    private definitions: Map<string, ExcelLibDefinition>;
    /**
     * 键值获取表格定义，Key:jsonName
     */
    private definitionTables: Map<String, ExcelLibDefinitionTable>;
    /**
     * 获取定义文件列表
     */
    private loadList: Array<ExcelLibDefinition>;

    private namespace: string = null;

    private loading: boolean;

    private serverHost: string = "";

    private isLoadFromCfgServer: boolean = false;

    constructor(libData: ExcelLibData) {
        this.libData = libData;
    }


    /**
     * 配置从配置服务器下载表
     * @param serverHost 服务器地址
     */
    public setLoadFromConfigServer(serverHost:string) {
        this.serverHost = serverHost;
        this.isLoadFromCfgServer = true;
    }

    /**
     * 配置从资源服务器下载表     
     */
    public setLoadFromResServer() {
        this.isLoadFromCfgServer = false;
    }


    private callbackDefinitionLoaded: Handler;

    
    /**
     * 加载_definitions.json
     * @returns 
     */
    public loadDefinition(callBack: Handler): boolean {
        this.loading = true;
        this.callbackDefinitionLoaded = callBack;
        Laya.loader.retryNum = 9;
        let url: string;
        if (this.isLoadFromCfgServer) {
            //构建从配置服务器下载的URL
            url = this.serverHost + ExcelLibReader.SERVER_DEFINITION_URL;
        } else {
            //从资源服务器下载的URL
            url = ExcelLibReader.FILE_RES_PATH + ExcelLibReader.FILE_DEFINITION;
        }
        Laya.loader.load( url, Laya.Handler.create(this, this.onDefinitionLoaded,
                [ExcelLibReader.FILE_DEFINITION]), null, Laya.Loader.JSON);
        return true;
    }

    /**
     * 加载_definitions.json完成，开始解析
     * @param resourceName 
     * @param json 
     */
    private onDefinitionLoaded(resourceName: string, json: JSON): void {
        console.log("onDefinitionLoaded -> " + resourceName)
        // 发布事件：下载Definition完毕，开始解析
        EventSystem.getInstance().dispatch(ExcelLib.EVENT_LIB_DEFINITION_DOWNLOADED);
        //加载header
        this.header = HeaderData.parseFromJson(json["header"])
        //加载定义
        const defines: Array<JSON> = json["defines"]
        //console.log(defines)
        let definitions: Map<string, ExcelLibDefinition> = new Map();
        let excelLibDefinitions: Array<ExcelLibDefinition> = new Array();
        for (const define of defines) {
            let edf = ExcelLibDefinition.parseFromJson(define)
            definitions.set(edf.getDataFullName(), edf);
            excelLibDefinitions.push(edf);
            //console.log(edf)
        }
        excelLibDefinitions.sort((a, b) => {
            return a.getLoadWeight() - b.getLoadWeight();
        })
        //加载表配置
        const tables: Array<JSON> = json["tables"];
        let definitionTables: Map<String, ExcelLibDefinitionTable> = new Map();
        for (const table of tables) {
            let tb = ExcelLibDefinitionTable.parseFromJson(table)
            definitionTables.set(tb.getJsonName(), tb);
        }     
        this.definitions = definitions;
        this.excelLibDefinitions = excelLibDefinitions;
        this.definitionTables = definitionTables;
        console.log("加载excelLibDefinitions完成。 版本：" + this.header.getVersion() + " MD5：" + this.header.getMd5());
        this.loading = false;
        // 回调告诉ExcelLib加载完成
        if (this.callbackDefinitionLoaded != null && this.callbackDefinitionLoaded != undefined) {
            this.callbackDefinitionLoaded.runWith(true);
        }
        // 发布事件：解析Definition完毕
        EventSystem.getInstance().dispatch(ExcelLib.EVENT_LIB_DEFINITION_COMPLETED);
    }


    /**
     * 加载指定数据表文件完成，开始解析
     * @param resourceName 
     * @param json 
     */
    private parseFromDownloadJson(df: ExcelLibDefinition, json: JSON): boolean {
        //console.log("onDataLoaded -> " + df.getClassName())
        //下载完毕，开始解析
        let result: any = null;
        switch (df.getType()) {
            case ExcelLibDefinition.LOAD_TYPE_LIST:
                result = ExcelLibTools.loadJsonList(json, df);
                break;
            case ExcelLibDefinition.LOAD_TYPE_MAP:
                if (df.getMainKeyType() == ExcelLibDefinition.FIELD_TYPE_INTEGER) {
                    result = ExcelLibTools.loadJsonIntMap(json, df);
                } else if (df.getMainKeyType() == ExcelLibDefinition.FIELD_TYPE_STRING) {
                    result = ExcelLibTools.loadJsonStringMap(json, df);
                }
                break;
            case ExcelLibDefinition.LOAD_TYPE_MAP2LIST:
                if (df.getMainKeyType() == ExcelLibDefinition.FIELD_TYPE_INTEGER) {
                    result = ExcelLibTools.loadJsonMapSetByIntegerKey(json, df);
                } else if (df.getMainKeyType() == ExcelLibDefinition.FIELD_TYPE_STRING) {
                    result = ExcelLibTools.loadJsonMapSetByStringKey(json, df);
                }
                break;
            case ExcelLibDefinition.LOAD_TYPE_MKMAP:
                result = ExcelLibTools.loadJsonMultKeyMap(json, df);
                break;
            default:
                console.log("配置数据包加载：加载索引方式类型错误：" + df.getType());
                return false
        }
        let table: ExcelLibDefinitionTable = this.definitionTables.get(df.getLoadJson())        
        if (result != null) {
            this.libData.getMaps().set(df.getDataFullName(), result);
            console.log("加载表[" + table.getComment() + "](" + table.getJsonName() + ") -> " + df.getDataFullName() + " 完成。 版本：" + table.getVersion() + " MD5：" + table.getMd5());
            // 发布事件：解析完毕
            EventSystem.getInstance().dispatch(ExcelLib.EVENT_LIB_LOAD_COMPLETED, [df.getDataFullName(), result]);
            return true;
        } else {
            // 发布事件：解析失败
            console.log("加载表[" + table.getComment() + "](" + table.getJsonName() + ") -> " + df.getDataFullName() + " 失败!! 版本：" + table.getVersion() + " MD5：" + table.getMd5());
            EventSystem.getInstance().dispatch(ExcelLib.EVENT_LIB_LOAD_FAIL, [df.getDataFullName()]);
            return false;
        }
    }

    /**
     * 从文件加载所有表数据
     * @param libData
     * @return
     */
    public loadAllData(): boolean {
        if (this.loading) {
            return false;
        }
        let res: Array<any> = new Array()
        this.loadList = new Array()
        for (let i = 0; i < this.excelLibDefinitions.length; i++) {
            let df: ExcelLibDefinition = this.excelLibDefinitions[i]
            let questUrl:string;
            if(this.isLoadFromCfgServer){
                //构建从配置服务器下载的URL
                questUrl = this.serverHost + ExcelLibReader.SERVER_TABLE_URL + df.getLoadJson() + ".json"
            }else{
                //从资源服务器下载的URL
                questUrl = ExcelLibReader.FILE_RES_PATH + df.getLoadJson() + ".json"
            }
            res.push({
                url: questUrl,
                type: Laya.Loader.JSON
            })
            this.loadList.push(df);
        }
        let count: number = res.length
        this.loading = true;

        Laya.loader.load(res,
            Laya.Handler.create(this, this.onLoadComplete),
            Laya.Handler.create(this, this.onProgress, null, false));
        EventSystem.getInstance().dispatch(ExcelLib.EVENT_LIB_LOAD_ALL_START, [this.loadList, count]);
        return true;
    }

    //加载完成后的回调函数
    public onProgress(process: number): void {
        // console.log("process:" + process);
        EventSystem.getInstance().dispatch(ExcelLib.EVENT_LIB_LOAD_PROCESS, [process]);
    }

    /** 资源加载完成时回调*/
    public onLoadComplete(isSuccess) {
        console.log("loadComplete:" + isSuccess);
        if (!isSuccess) {
            this.loadList = null;
            this.loading = false;
            EventSystem.getInstance().dispatch(ExcelLib.EVENT_LIB_LOAD_DOWNLOADED, [this.loadList, false]);
            return;
        } else {
            EventSystem.getInstance().dispatch(ExcelLib.EVENT_LIB_LOAD_DOWNLOADED, [this.loadList, true]);
        }
        // 根据loadWeight权重排序解析
        this.loadList.sort((a, b) => {
            return a.getLoadWeight() - b.getLoadWeight()
        })
        let result: boolean = true;
        for (let i = 0; i < this.loadList.length; i++) {
            let df: ExcelLibDefinition = this.loadList[i];
            let questUrl:string;
            if(this.isLoadFromCfgServer){
                //构建从配置服务器下载的URL
                questUrl = this.serverHost + ExcelLibReader.SERVER_TABLE_URL + df.getLoadJson() + ".json"
            }else{
                //从资源服务器下载的URL
                questUrl = ExcelLibReader.FILE_RES_PATH + df.getLoadJson() + ".json"
            }
            let json: JSON = Laya.loader.getRes(questUrl);            
            result = result && this.parseFromDownloadJson(df, json);
        }
        this.loadList = null;
        this.loading = false;
        EventSystem.getInstance().dispatch(ExcelLib.EVENT_LIB_LOAD_ALL_COMPLETED, [this.loadList, result]);
    }

    /**
     * 根据组别加载表数据
     * @param gruopName 组别名。可使用常量ExcelLibDataEasyAccess.GROUP_*
     * @return
     */
    public loadFromGroup(gruopName: string): number {
        if (this.loading) {
            return -1;
        }
        this.loadList = new Array()
        for (let i = 0; i < this.excelLibDefinitions.length; i++) {
            let df: ExcelLibDefinition = this.excelLibDefinitions[i];
            if (gruopName == df.getGroup()) {
                this.loadList.push(df);
            }
        }
        let res: Array<any> = new Array()
        for (let df2 of this.loadList) {
            let questUrl:string;
            if(this.isLoadFromCfgServer){
                //构建从配置服务器下载的URL
                questUrl = this.serverHost + ExcelLibReader.SERVER_TABLE_URL + df2.getLoadJson() + ".json"
            }else{
                //从资源服务器下载的URL
                questUrl = ExcelLibReader.FILE_RES_PATH + df2.getLoadJson() + ".json"
            }
            res.push({
                url: questUrl,
                type: Laya.Loader.JSON
            })
        }
        let count: number = res.length
        this.loading = true;
        Laya.loader.load(res,
            Laya.Handler.create(this, this.onLoadComplete),
            Laya.Handler.create(this, this.onProgress, null, false)
        );
        // 发布事件：开始下载
        EventSystem.getInstance().dispatch(ExcelLib.EVENT_LIB_LOAD_GROUP_START, [this.loadList, count]);
        return count;
    }

    /**
     * 根据表索引名字加载文件
     * @param dataFullName 
     * @returns 
     */
    public loadFromFileByName(dataFullName: string, isLoadRelations: boolean): number {
        if (this.loading) {
            return 0;
        }
        let df: ExcelLibDefinition = this.definitions.get(dataFullName);
        if (df == null) {
            console.log("加载错误的Excel数据，数据表全名：" + dataFullName);
            return null;
        }
        this.loadList = new Array()
        if (isLoadRelations == false) {
            //加载单个文件
            this.loadList.push(df)
        } else {
            //加载单个文件及关联文件
            let loadDefinitions: Map<String, ExcelLibDefinition> = new Map();
            this.recursionSearchRelation(loadDefinitions, df);
            for (let df2 of loadDefinitions.values()) {
                this.loadList.push(df2);
            }
        }
        let res: Array<any> = new Array()
        for (let df2 of this.loadList) {
            let questUrl:string;
            if(this.isLoadFromCfgServer){
                //构建从配置服务器下载的URL
                questUrl = this.serverHost + ExcelLibReader.SERVER_TABLE_URL + df2.getLoadJson() + ".json"
            }else{
                //从资源服务器下载的URL
                questUrl = ExcelLibReader.FILE_RES_PATH + df2.getLoadJson() + ".json"
            }
            res.push({
                url: questUrl,
                type: Laya.Loader.JSON
            })
        }
        let count: number = res.length
        this.loading = true;
        Laya.loader.load(res,
            Laya.Handler.create(this, this.onLoadComplete),
            Laya.Handler.create(this, this.onProgress, null, false)
        );
        // 发布事件：开始下载
        EventSystem.getInstance().dispatch(ExcelLib.EVENT_LIB_LOAD_START, [this.loadList, count]);
    }

    /**
     * 递归找出关联需要加载的表
     * @param loadDefinitions 
     * @param current 
     */
    private recursionSearchRelation(loadDefinitions: Map<String, ExcelLibDefinition>, current: ExcelLibDefinition) {
        loadDefinitions.set(current.getDataFullName(), current);
        for (let rJsonName of current.getLoadRelations()) {
            for (let searchDefinition of this.excelLibDefinitions) {
                if (rJsonName == searchDefinition.getLoadJson()) {
                    if (!loadDefinitions.has(searchDefinition.getDataFullName())) {
                        this.recursionSearchRelation(loadDefinitions, searchDefinition);
                    }
                }
            }
        }
    }

    public getServerHost(): string {
        return this.serverHost;
    }

    public setServerHost(serverHost: string) {
        this.serverHost = serverHost;
    }
}